home *** CD-ROM | disk | FTP | other *** search
/ Super PC 33 / Super PC 33 (Shareware).iso / spc / sonido / timidity / source / win_aud.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-08-17  |  5.2 KB  |  249 lines

  1. /*
  2.  
  3.     TiMidity -- Experimental MIDI to WAVE converter
  4.     Copyright (C) 1995 Tuukka Toivonen <titoivon@snakemail.hut.fi>
  5.  
  6.      This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.      the Free Software Foundation; either version 2 of the License, or
  9.      (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.      GNU General Public License for more details.
  15.  
  16.      You should have received a copy of the GNU General Public License
  17.      along with this program; if not, write to the Free Software
  18.      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20.     win_audio.c
  21.  
  22.     Functions to play sound on the Win32 audio driver (Win 95 or Win NT).
  23.  
  24. */
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <windows.h>
  30.  
  31. #include "config.h"
  32. #include "output.h"
  33. #include "controls.h"
  34.  
  35. static int open_output(void); /* 0=success, 1=warning, -1=fatal error */
  36. static void close_output(void);
  37. static void output_data(int32 *buf, int32 count);
  38. static void flush_output(void);
  39. static void purge_output(void);
  40.  
  41. /* export the playback mode */
  42.  
  43. #define dpm win32_play_mode
  44.  
  45. PlayMode dpm = {
  46.   DEFAULT_RATE, PE_16BIT|PE_SIGNED,
  47.   -1,
  48.   {0},
  49.   "Win32 audio driver", 'd',
  50.   NULL,
  51.   open_output,
  52.   close_output,
  53.   output_data,
  54.   flush_output,
  55.   purge_output
  56. };
  57.  
  58. /* Max audio blocks waiting to be played */
  59. #define MAX_BLOCKS 4
  60.  
  61. static LPHWAVEOUT dev;
  62. static int nBlocks;
  63.  
  64. extern CRITICAL_SECTION critSect;
  65.  
  66. static void wait (void)
  67.     {
  68.     while (nBlocks)
  69.         Sleep (0);
  70.     }
  71.  
  72. static int play (void *mem, int len)
  73.     {
  74.     HGLOBAL hg;
  75.     LPWAVEHDR wh;
  76.     MMRESULT res;
  77.  
  78. /*    while (nBlocks > MAX_BLOCKS)
  79.         Sleep (0); */
  80.  
  81.     hg = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof (WAVEHDR));
  82.     if (!hg)
  83.         {
  84.         ctl->cmsg (CMSG_INFO, VERB_NORMAL, "GlobalAlloc failed!");
  85.         return FALSE;
  86.         }
  87.     wh = GlobalLock (hg);
  88.     wh->dwBufferLength = len;
  89.     wh->lpData = mem;
  90.  
  91.     res = waveOutPrepareHeader (dev, wh, sizeof (WAVEHDR));
  92.     if (res)
  93.         {
  94.         ctl->cmsg (CMSG_INFO, VERB_NORMAL, "waveOutPrepareHeader: %d", res);
  95.         GlobalUnlock (hg);
  96.         GlobalFree (hg);
  97.         return TRUE;
  98.         }
  99.     res = waveOutWrite (dev, wh, sizeof (WAVEHDR));
  100.     if (res)
  101.         {
  102.         ctl->cmsg (CMSG_INFO, VERB_NORMAL, "waveOutWrite: %d", res);
  103.         GlobalUnlock (hg);
  104.         GlobalFree (hg);
  105.         return TRUE;
  106.         }
  107.     EnterCriticalSection (&critSect);
  108.     nBlocks++;
  109.     LeaveCriticalSection (&critSect);
  110. //    cmsg (CMSG_INFO,VERB_NOISY, "Play: %d blocks", nBlocks);
  111.     return FALSE;
  112.     }
  113.  
  114. #pragma argsused
  115. static void CALLBACK wave_callback (HWAVE hWave, UINT uMsg,
  116.         DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
  117.     {
  118.     WAVEHDR *wh;
  119.     HGLOBAL hg;
  120.  
  121.     if (uMsg == WOM_DONE)
  122.         {
  123.         EnterCriticalSection (&critSect);
  124.         wh = (WAVEHDR *)dwParam1;
  125.         waveOutUnprepareHeader (dev, wh, sizeof (WAVEHDR));
  126.         hg = GlobalHandle (wh->lpData);
  127.         GlobalUnlock (hg);
  128.         GlobalFree (hg);
  129.         hg = GlobalHandle (wh);
  130.         GlobalUnlock (hg);
  131.         GlobalFree (hg);
  132.         nBlocks--;
  133.         LeaveCriticalSection (&critSect);
  134. //        cmsg (CMSG_INFO, VERB_NOISY, "Callback: %d blocks", nBlocks);
  135.         }
  136.     }
  137.  
  138. static int open_output (void)
  139.     {
  140.     int i, j, mono, eight_bit, warnings = 0;
  141.     PCMWAVEFORMAT pcm;
  142.     MMRESULT res;
  143.  
  144.     /* Check if there is at least one audio device */
  145.     if (!waveOutGetNumDevs ())
  146.         {
  147.         ctl->cmsg (CMSG_ERROR, VERB_NORMAL, "No audio devices present!");
  148.         return -1;
  149.         }
  150.  
  151.     /* They can't mean these */
  152.     dpm.encoding &= ~(PE_ULAW|PE_BYTESWAP);
  153.  
  154.     if (dpm.encoding & PE_16BIT)
  155.         dpm.encoding |= PE_SIGNED;
  156.     else
  157.         dpm.encoding &= ~PE_SIGNED;
  158.  
  159.     mono = (dpm.encoding & PE_MONO);
  160.     eight_bit = !(dpm.encoding & PE_16BIT);
  161.  
  162.     pcm.wf.wFormatTag = WAVE_FORMAT_PCM;
  163.     pcm.wf.nChannels = mono ? 1 : 2;
  164.     pcm.wf.nSamplesPerSec = i = dpm.rate;
  165.     j = 1;
  166.     if (!mono)
  167.         {
  168.         i *= 2;
  169.         j *= 2;
  170.         }
  171.     if (!eight_bit)
  172.         {
  173.         i *= 2;
  174.         j *= 2;
  175.         }
  176.     pcm.wf.nAvgBytesPerSec = i;
  177.     pcm.wf.nBlockAlign = j;
  178.     pcm.wBitsPerSample = eight_bit ? 8 : 16;
  179.  
  180.     res = waveOutOpen (NULL, 0, (LPWAVEFORMAT)&pcm, NULL, 0, WAVE_FORMAT_QUERY);
  181.     if (res)
  182.         {
  183.         ctl->cmsg (CMSG_ERROR, VERB_NORMAL, "Format not supported!");
  184.         return -1;
  185.         }
  186.     res = waveOutOpen (&dev, 0, (LPWAVEFORMAT)&pcm, (DWORD)wave_callback, 0, CALLBACK_FUNCTION);
  187.     if (res)
  188.         {
  189.         ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Can't open audio device");
  190.         return -1;
  191.         }
  192.     return warnings;
  193.     }
  194.  
  195. static void output_data (int32 *buf, int32 count)
  196.     {
  197.     int len = count;
  198.     HGLOBAL hg;
  199.     void *b;
  200.  
  201.     if (!(dpm.encoding & PE_MONO)) /* Stereo sample */
  202.         {
  203.         count *= 2;
  204.         len *= 2;
  205.         }
  206.  
  207.     if (dpm.encoding & PE_16BIT)
  208.         len *= 2;
  209.  
  210.     hg = GlobalAlloc (GMEM_MOVEABLE, len);
  211.     if (!hg)
  212.         {
  213.         ctl->cmsg (CMSG_INFO, VERB_NORMAL, "GlobalAlloc failed!");
  214.         return;
  215.         }
  216.     b = GlobalLock (hg);
  217.  
  218.     if (dpm.encoding & PE_16BIT)
  219.         /* Convert data to signed 16-bit PCM */
  220.         s32tos16 (buf, b, count);
  221.     else
  222.         /* Convert to 8-bit unsigned. */
  223.         s32tou8 (buf, b, count);
  224.  
  225.     if (play (b, len))
  226.         {
  227.         GlobalUnlock (hg);
  228.         GlobalFree (hg);
  229.         }
  230.     }
  231.  
  232. static void close_output (void)
  233.     {
  234.     wait ();
  235.     waveOutClose (dev);
  236.     }
  237.  
  238. static void flush_output (void)
  239.     {
  240.     wait ();
  241.     }
  242.  
  243. static void purge_output (void)
  244.     {
  245.     waveOutReset (dev);
  246.     wait ();
  247.     }
  248.  
  249.